import React, { useMemo, useState } from 'react';
import LazyLoad from '../lazy-load';
import { useRem } from '../utils/global';
import './image.less';
import { Placeholder } from './placeholder';
import { CDNOptions, useCDN } from './use-cdn';

const classPrefix = `bbt-react-image`;

export type ImageUseOptions = {
  /** image全局选项 */
  px2rem?: (px: number) => string;
  [key: string]: any;
};

export type ImageProps = {
  /** 图片地址 */
  src: string;
  /** 图片宽度 */
  width?: number;
  /** 图片高度 */
  height?: number;
  /** 图片描述 */
  alt?: string;
  /** 图片填充模式 */
  fitMode?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
  /** 图片懒加载 */
  lazyLoad?: boolean;
  /** 图片点击 */
  onClick?: (event: React.MouseEvent<HTMLImageElement, Event>) => void;
  /** 图片容器点击 */
  onContainerClick?: (event: React.MouseEvent<HTMLDivElement, Event>) => void;
  /** 图片加载失败 */
  onError?: (event: React.SyntheticEvent<HTMLImageElement, Event>) => void;
  /** 图片加载成功 */
  onLoad?: (event: React.SyntheticEvent<HTMLImageElement, Event>) => void;
  /** 加载中展示 */
  placeholder?: React.ReactNode;
  /** 加载失败展示 */
  fallback?: React.ReactNode;
  /** 显示内联/块级 */
  display?: 'inline' | 'block' | 'inline-block';
  /** css样式 */
  styles?: React.CSSProperties;
  /** className */
  className?: string;
  /** 容器class */
  containerClassName?: string;
  /** 懒加载滚动容器, 默认浏览器视窗 */
  container?: Element | Document | null | undefined;
  /** 七牛CDN裁剪 */
  qiniu?: CDNOptions | boolean;
  /** px转换rem方法 */
  px2rem?: (px: number) => string;
} & Pick<
  React.ImgHTMLAttributes<HTMLImageElement>,
  | 'crossOrigin'
  | 'decoding'
  | 'loading'
  | 'referrerPolicy'
  | 'sizes'
  | 'srcSet'
  | 'useMap'
>;

const Image: any = (props: ImageProps) => {
  const {
    fitMode = 'fill',
    lazyLoad = false,
    display = 'inline-block',
    styles = {},
    className,
  } = props;

  const [loaded, setLoaded] = useState(false);
  const [failed, setFailed] = useState(false);
  const [init, setInit] = useState(!lazyLoad);

  const usePx2rem = useRem(props?.px2rem);

  const width = useMemo(() => {
    return usePx2rem(props?.width);
  }, [props?.px2rem, props?.width]);

  const height = useMemo(() => {
    return usePx2rem(props?.height);
  }, [props?.px2rem, props?.height]);

  const src = useMemo(
    () => (init ? props.src || undefined : undefined),
    [init, props.src],
  );
  const srcSet = useMemo(
    () => (init ? props.srcSet || undefined : undefined),
    [init, props.srcSet],
  );

  const [cdnSrc] = useCDN({
    src,
    width: props?.width,
    height: props?.height,
    options: typeof props?.qiniu === 'object' ? props?.qiniu : {},
    open: Boolean(props?.qiniu),
  });

  const PlaceholderRender = useMemo(() => {
    return (
      <div
        className={`${classPrefix}-placeholder`}
        style={{
          width: width,
          height: height,
        }}
      >
        <Placeholder></Placeholder>
      </div>
    );
  }, [width, height]);

  const placeholder = props?.placeholder || PlaceholderRender;
  const fallback = props?.fallback || PlaceholderRender;

  const RenderImg = () => {
    if (failed) {
      return fallback;
    }
    return (
      <>
        {!loaded ? placeholder : null}
        <img
          src={props?.qiniu ? cdnSrc : src}
          srcSet={srcSet}
          crossOrigin={props.crossOrigin}
          decoding={props.decoding}
          loading={props.loading}
          referrerPolicy={props.referrerPolicy}
          sizes={props.sizes}
          useMap={props.useMap}
          style={{
            objectFit: fitMode,
            width: width,
            height: height,
            ...styles,
          }}
          className={className}
          onClick={props.onClick}
          onLoad={(e) => {
            setLoaded(true);
            props.onLoad?.(e);
          }}
          onError={(e) => {
            setFailed(true);
            props.onError?.(e);
          }}
        />
      </>
    );
  };

  return (
    <div
      onClick={props.onContainerClick}
      style={{
        display,
        width: width,
        height: height,
      }}
      className={`${classPrefix} ${props?.containerClassName || ''}`}
    >
      {lazyLoad && !init ? (
        <LazyLoad
          onVisible={(visible) => {
            visible && setInit(visible);
          }}
          container={props?.container || null}
        >
          <div style={{ width: '1px', height: '1px' }}></div>
        </LazyLoad>
      ) : (
        RenderImg()
      )}
    </div>
  );
};

Image.options = null;

Image.use = (options: ImageUseOptions) => {
  if (options) {
    Image.options = options;
  }
};

export { Image };
